home *** CD-ROM | disk | FTP | other *** search
- // midisort v1.0 written by Günter Nagler 1995 (gnagler@ihm.tu-graz.ac.at)
- #include "midiio.hpp"
- #include "mtrack.hpp"
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <ctype.h>
- #ifdef __MSDOS__
- #include <alloc.h>
- #endif
-
- class MidiCopyTrack;
-
- char* input = 0;
- char* output = 0;
-
- #define MAXTRACKS 150
-
- int sortbychannel = 0;
- int moveempty = 0;
- int manualorder[MAXTRACKS];
- int manualcnt = 0;
- int showtracks = 0;
- int order[MAXTRACKS];
-
- MidiWrite* write = 0;
- MidiTrackinfo* info = 0;
-
- class MidiCopyTrack : public MidiRead
- {
- public:
- MidiCopyTrack(char* name, FILE* f = 0);
-
- virtual void track(int trackno, long length, int channel);
- virtual void endtrack(int trackno);
- virtual void time(unsigned long ticks);
-
- virtual void program(int prg, int channel);
- virtual void control(int channel, int what, int value);
- virtual void noteon(int channel, int note, int vel);
- virtual void noteoff(int channel, int note, int vel);
- virtual void pitchbend(int channel, int val);
- virtual void polyaftertouch(int channel, int note, int val);
- virtual void aftertouch(int channel, int val);
- virtual void songpos(unsigned pos);
- virtual void songselect(unsigned char song);
- virtual void tunerequest();
- virtual void timingclock();
- virtual void start();
- virtual void cont();
- virtual void stop();
- virtual void activesense();
- virtual void sysex(int syslen, unsigned char* sysdata);
- virtual void meta(int what, int len, unsigned char* data);
- virtual void error(const char* msg);
- };
-
- MidiCopyTrack::MidiCopyTrack(char* name, FILE* f) : MidiRead(name, f)
- {
- options_ = OPTION_NOCONTROLS+OPTION_NOSYSEVENTS;
- }
-
- void MidiCopyTrack::track(int trackno, long length, int channel)
- {
- write->track();
- }
-
- void MidiCopyTrack::endtrack(int trackno)
- {
- write->endtrack();
- }
-
- void MidiCopyTrack::time(unsigned long ticks)
- {
- write->time(ticks);
- }
-
-
- void MidiCopyTrack::meta(int what, int len, unsigned char* data)
- {
- write->meta(what, len, data);
- }
-
- void MidiCopyTrack::program(int channel, int prg)
- {
- write->program(channel, prg);
- }
-
- void MidiCopyTrack::control(int channel, int what, int value)
- {
- write->control(channel, what, value);
- }
-
- void MidiCopyTrack::noteon(int channel, int note, int vel)
- {
- write->noteon(channel, note, vel);
- }
-
- void MidiCopyTrack::noteoff(int channel, int note, int vel)
- {
- write->noteoff(channel, note, vel);
- }
-
- void MidiCopyTrack::pitchbend(int channel, int val)
- {
- write->pitchbend(channel, val);
- }
-
- void MidiCopyTrack::polyaftertouch(int channel, int note, int val)
- {
- write->polyaftertouch(channel, note, val);
- }
-
- void MidiCopyTrack::aftertouch(int channel, int val)
- {
- write->aftertouch(channel, val);
- }
-
- void MidiCopyTrack::songpos(unsigned pos)
- {
- write->songpos(pos);
- }
-
- void MidiCopyTrack::songselect(unsigned char song)
- {
- write->songselect(song);
- }
-
- void MidiCopyTrack::tunerequest()
- {
- write->tunerequest();
- }
-
- void MidiCopyTrack::timingclock()
- {
- write->timingclock();
- }
-
- void MidiCopyTrack::start()
- {
- write->start();
- }
-
- void MidiCopyTrack::cont()
- {
- write->cont();
- }
-
- void MidiCopyTrack::stop()
- {
- write->stop();
- }
-
- void MidiCopyTrack::activesense()
- {
- write->activesense();
- }
-
- void MidiCopyTrack::sysex(int syslen, unsigned char* sysdata)
- {
- write->sysex(syslen, sysdata);
- }
-
- void MidiCopyTrack::error(const char* msg)
- {
- printf("// error: %s\n", msg);
- exit(1);
- }
-
-
- void movetrack(int from, int to)
- {
- if (from == to)
- return;
- int t = order[from];
-
- if (from > to)
- {
-
- for (int i = from; i > to; i--)
- order[i] = order[i-1];
- order[i] = t;
- }
- else if (to > from)
- {
- for (int i = from; i < to; i++)
- order[i] = order[i+1];
- order[i] = t;
- }
- }
-
- void midisort()
- {
- int trk;
-
- if (info->trackcount() >= MAXTRACKS)
- {
- fprintf(stderr, "Too many tracks. Cannot sort\n");
- exit(1);
- }
- for (trk = 0; trk < info->trackcount(); trk++) // default: no sorting
- order[trk] = trk+1;
-
- if (manualcnt > 0)
- {
- int n = 1;
-
- // manual order
- for (int i = 0; i < manualcnt; i++)
- {
- // search for duplicates
- for (int j = i+1; j < manualcnt; j++)
- if (manualorder[j] == manualorder[i])
- break;
- if (j < manualcnt)
- continue; // ignore duplicate order numbers
-
- if (i > 0 && manualorder[i] == 1)
- {
- fprintf(stderr, "track 1 cannot be moved!\n");
- continue;
- }
- // search for current track order
- for (j = 0; j < info->trackcount(); j++)
- if (manualorder[i] == order[j])
- break;
- if (j >= info->trackcount()) // track does not exist
- continue;
- movetrack(j, n++);
- }
- // other tracks remain the same
- }
- if (moveempty)
- {
- // move empty comment tracks to end of midi file
- // reason: some players limit number of tracks and then
- // empty tracks are loaded and important are ommitted
- for (trk = 1; trk < info->trackcount(); trk++)
- {
- // order[1..trk-1] have channel != NOCHANNEL!
-
- int k;
-
- for (k = trk; k < info->trackcount(); k++)
- if (info->trackinfo(order[k])->channel_ != NOCHANNEL)
- break;
- if (k >= info->trackcount())
- break;
-
- movetrack(k, trk);
- }
- }
-
- if (sortbychannel)
- {
- for (trk = 1; trk < info->trackcount(); trk++)
- if (info->trackinfo(order[trk])->channel_ >= 0)
- {
- // order[1..trk-1] are sorted!
-
- int k, bestk;
-
- bestk = -1;
- for (k = trk; k < info->trackcount(); k++)
- if (info->trackinfo(order[k])->channel_ >= 0)
- {
- if (bestk < 0 ||
- info->trackinfo(order[k])->channel_ < info->trackinfo(order[bestk])->channel_)
- {
- bestk = k;
- }
- }
- if (bestk < 0)
- break;
- movetrack(bestk, trk);
- }
- }
-
- assert(order[0] == 1); // do not move first track!
-
- for (trk = 0; trk < info->trackcount(); trk++)
- if (order[trk] != trk+1)
- break;
- if (trk >= info->trackcount())
- fprintf(stderr, "Tracks of %s are already sorted. Building a safe copy.\n", input);
-
- write = new MidiWrite(output); assert(write != 0);
- write->head(info->version_,0, info->unitsperbeat_);
-
- MidiCopyTrack copy(input);
- for (trk = 0; trk < info->trackcount(); trk++)
- {
- // printf("writing track #%d\n", order[trk]);
- copy.seek(info->trackinfo(order[trk])->pos_);
- copy.runtrack(trk+1);
- }
- delete write; // close midi file
- fprintf(stderr, "output written to %s\n", output);
- }
-
- void usage()
- {
- fprintf(stderr, "usage: midisort [-track] [-order # ...] [-channel][-moveempty] srcfile.mid dstfile.mid\n");
- fprintf(stderr, "sorts tracks of a midi file or generates a duplicate.\n");
- fprintf(stderr, "-track\t\tshow tracks\n");
- fprintf(stderr, "-order # ...\tdefine order of tracks (e.g. 1 3 2)\n");
- fprintf(stderr, "-channel\tsort by channel numbers\n");
- fprintf(stderr, "-moveempty\tmove empty or comment tracks to end of midi\n");
- exit(1);
- }
-
- int main(int argc, char** argv)
- {
- argc--; argv++;
-
- while (argc > 0 && **argv == '-')
- {
- if (strncmp(*argv, "-track", 2) == 0)
- {
- showtracks = 1;
- argc--; argv++; continue;
- }
- else if (strncmp(*argv, "-channel", 2) == 0)
- {
- sortbychannel = 1;
- argc--; argv++; continue;
- }
- else if (strncmp(*argv, "-moveempty", 2) == 0)
- {
- moveempty = 1;
- argc--; argv++; continue;
- }
- else if (strncmp(*argv, "-order", 2) == 0)
- {
- argc--; argv++;
- if (argc == 0 || !isdigit(**argv))
- fprintf(stderr, "option -order needs tracknumbers as parameters\n");
- while (argc > 0 && isdigit(**argv) && manualcnt < MAXTRACKS)
- {
- int order;
-
- if (sscanf(*argv, "%d", &order) != 1)
- {
- fprintf(stderr, "parameters of option -order must be numbers between 1 and %d\n",
- MAXTRACKS);
- exit(1);
- }
- else if (order <= 0)
- {
- fprintf(stderr, "invalid order number %s (should be 1..%d)\n",
- *argv, MAXTRACKS);
- exit(1);
- }
- else
- {
- manualorder[manualcnt++] = order;
- }
- argc--; argv++;
- }
- continue;
- }
- fprintf(stderr, "invalid option %s\n", *argv);
- argc--; argv++;
- usage();
- }
-
- if (argc <= 0)
- usage();
-
- input = *argv++; argc--;
- info = new MidiTrackinfo(input); assert(info != 0);
- if (!info->getf())
- {
- fprintf(stderr, "could not open %s\n", input);
- delete info;
- exit(1);
- }
-
- if (showtracks)
- {
- info->print(stdout);
- delete info;
- exit(0);
- }
-
- if (argc <= 0)
- usage();
-
- output = *argv++; argc--;
- if (strcmp(input, output) == 0)
- {
- fprintf(stderr, "cannot sort midi to same file\n");
- return 1;
- }
-
- midisort();
-
- delete info;
- return 0;
- }